use vhdl_lang::Project;

use vhdl_lang::ast::*;
use super::utils::*;
use super::units;
use super::peephole;
use super::expression::{Expr};
use vhdl_lang::data::WithPos;

use std::fmt;
use fnv::FnvHashMap;
pub use std::path::Path;

#[derive(PartialEq, Clone, Debug)]
pub struct Interface {
    pub ident   : String,
    pub mode    : Mode,
    pub subtype : String,
}

impl Interface {
    pub fn from_obj(port:&InterfaceObjectDeclaration) -> Interface {
        let mut result = format!("{}",subtype2spinal(&port.subtype_indication));
        let rules = peephole::Rules{};
        if let Some(e) = port.expression.clone() {
            result += &to_str(&e);
        };
        result = rules.done(result);
        let ident = format!("{}",port.ident.name().name());
        let mode = port.mode.clone();
        Interface {
            ident,
            mode,
            subtype : result,
        }  
    }
    pub fn from(ip:&InterfaceDeclaration) -> Interface {
        match ip {
            InterfaceDeclaration::Object(port) =>  Self::from_obj(port),
            _ => Interface{
                ident:String::new(),
                mode: Mode::In,
                subtype:String::new(),
            },
        }             
    }
    pub fn generic_str(&self) -> String {
        format!("val {} = {}", self.ident,self.subtype)
    }
    pub fn port_strs(&self) -> (String,String) {
        let mode = match self.mode {
            Mode::In => "in ",
            Mode::Out => "out",
            Mode::InOut => "inout",
            _ => "",
        };
        (format!("{}",self.ident),format!("{} {}",mode,self.subtype))
    }
}

impl fmt::Display for Interface {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let (id,sub) = self.port_strs();
        write!(f, "val {} = {}", id,sub)
    }
}

#[derive(PartialEq, Clone, Debug)]
pub struct Entity {
    pub ident        : String,
    pub generic_list : Option<Vec<Interface>>,
    pub ports        : Option<Vec<Interface>>,
    pub file         : String,
}

impl Entity {
    pub fn from(en:&EntityDeclaration) -> Entity {
        let file = format!("{}",en.ident.pos.source.file_name().to_str().unwrap());
        let ident = to_str(&en.ident);
        let generic = en.generic_clause
            .as_ref()
            .map(|generic| 
                generic
                    .iter()
                    .map(|x| Interface::from(x))
                    .collect::<Vec<_>>()
                );
        let ports   = en.port_clause
            .as_ref()
            .map(|port| 
                port
                    .iter()
                    .map(|x| Interface::from(x))
                    .collect::<Vec<_>>()
                );
        Entity {
            ident,
            generic_list :generic,
            ports,
            file,
        }        
    }
    fn io_bundle(self,times:usize) -> String {
        if let Some(ports) = self.ports {
            val( ports.iter().map(|port| port.port_strs()).collect(),times)
        } else {
            String::new()
        }
    }
    pub fn dumb_case_class(&self,body:Vec<String>) -> String {
        let mut result = format!("case class {}(",self.ident);
        if let Some(generic) = self.generic_list.clone() {
            let mut first = true;
            for line in generic.iter()
                .map(|g| g.generic_str()) {
                    if first {
                        first = false;
                    } else {
                        result += ",";
                    }
                    result += &line;
                }
        }
        result += ") extends Component {\n";
        result += "  val io = new Bundle {\n";
        let io = self.clone().io_bundle(4);
        result += &io;
        result += "  }\n";
        result += &body.join("\n");
        result += "\n}\n";
        result
    }
    pub fn all(project: &Project) -> Vec<Entity> {
        let mut result = Vec::new();
        for file in project.files() {
            for en in units::entity(&file.get_design_file()) {
                result.push(Entity::from(&en));
            }
        }
        result 
    }
}

#[derive(PartialEq, Debug, Clone)]
pub struct AssElement {
    pub formal: Option<String>,
    pub actual: String,
}
impl AssElement {
    pub fn from(ae:&AssociationElement) -> AssElement {
        let actual = to_str(&ae.actual);
        let formal = ae.formal.as_ref().map(|name| to_str(&name));
        AssElement { 
            formal,
            actual,
        }
    }
    pub fn val(&self) -> String {
        match &self.formal {
            Some(f) => format!("{}={}", f, self.actual),
            None    => format!("{}", self.actual),
        }
    }
}
#[derive(PartialEq, Debug, Clone)]
pub enum Unit {
    Entity(Entity),
    BlackBox(String)
}
#[derive(PartialEq, Debug, Clone)]
pub struct Instance {
    pub label: String,
    pub unit : Option<Unit>,
    pub generic_map: Vec<AssElement>,
    pub port_map: Vec<AssElement>,
    pub entity_name:String,
}

impl Instance {
    pub fn from(d:&LabeledConcurrentStatement,base: &Database) -> Option<Instance> {
        match d.statement.clone() {
            ConcurrentStatement::Instance(u) => { 
                let label = format!("{}",d.label.clone().unwrap().item.name());
                let mut entity_name = String::new();
                let unit = { 
                    match u.unit {
                        InstantiatedUnit::Component(c) => {
                            entity_name = format!("{}",c.item);
                            if let Some(u) = base.get_entity(format!("{}",c.item)) {
                                Some(Unit::Entity(u.clone()))
                            } else {
                                Some(Unit::BlackBox(format!("{}_blackbox",c.item)))
                            }
                        },
                        _ => None,
                    }
                };
                let generic_map = u.generic_map.iter().map(|a| AssElement::from(a)).collect::<Vec<_>>();
                let port_map = u.port_map.iter().map(|a| AssElement::from(a)).collect::<Vec<_>>();
                Some(Instance {
                    label,
                    unit,
                    generic_map,
                    port_map,
                    entity_name,
                })
            }
            _ => None
        }
    }
    pub fn declare(&self) -> (String,String) {
        let mut comp = String::new();
        if let Some(u) = &self.unit {
            match u {
                Unit::Entity(u) => {comp += &format!("{}",u.ident);},
                Unit::BlackBox(s) => {comp += &s;}
            }
        } 
        comp += "(";
        let mut args = String::new();
        let mut first = true;
        for g in self.generic_map.clone() {
            if first {
                first = false;
            } else {
                args += ",";
            }
            args += &g.val();
        }
        if args.len()>10 {
            comp += &args[0..10];
            comp += "...";
        } else {
            comp += &args;
        }
        comp += ")";
        (self.label.clone(),comp)
    }
}

#[derive(PartialEq, Debug, Clone)]
pub struct Component {
    pub name : String,
    pub entity : Option<Entity>,
    pub generic_list: Vec<Interface>,
    pub port_list: Vec<Interface>,
}
impl Component {
    pub fn from(d:&ComponentDeclaration,base: &Database) -> Component {
        let generic_list = d.generic_list.iter()
                .map(|x| Interface::from(x))
                .collect::<Vec<_>>();
        let port_list = d.port_list.iter()
                .map(|x| Interface::from(x))
                .collect::<Vec<_>>();
        let name = format!("{}",d.ident.item);
        let en   = if let Some(u) = base.get_entity(name.clone()) {Some(u.clone())} else {None};
        Component {
            name,
            entity:en,
            generic_list,
            port_list,
        }
    }
    pub fn mode(&self,id:&String) -> Option<Mode> {
        let mut mode : Option<Mode> = None;
        for p in &self.port_list {
            if p.ident == id.clone() {
                mode = Some(p.mode);
            }
        }
        mode
    }
}

#[derive(PartialEq, Debug, Clone)]
pub struct Architecture {
    pub instances  : FnvHashMap<String, Instance>,
    pub components : FnvHashMap<String, Component>,
}

impl Architecture {
    pub fn from(arch:&ArchitectureBody,base:&Database) -> Architecture {
        let mut instances = FnvHashMap::default();
        for d in arch.statements.clone() {
            if let Some(i) = Instance::from(&d,base) {
                instances.insert(i.label.clone(),i.clone());
            }
        }
        let mut components = FnvHashMap::default();
        for d in &arch.decl {
            match d {
                Declaration::Component(c) => {
                    let com = Component::from(&c, base);
                    components.insert(com.name.clone(),com);
                }
                _ => (),
            }
        }
        Architecture {
            instances,
            components,
        }
    }
    pub fn instances_strings(&self) -> Vec<String> {
        let mut result = Vec::new();
        for (_,instance) in self.instances.clone() {
            result.push(instance.declare())
        }
        vals(result,2)
    }
    pub fn mode(&self,name:&String,port:&String) -> Mode {
        if let Some(com) = self.components.get(name) {
            match com.mode(port) {
                Some(m) => m,
                None => Mode::In,
            }
        } else {
            Mode::In
        }
    }
    pub fn instances_io_strings(&self) -> Vec<String> {
        let mut result = Vec::new();
        for (_,d) in &self.instances {
            let mut one_com = Vec::new();
            let io = format!("{}.io.",d.label);
            for g in &d.port_map {
                if let Some(gf) = &g.formal {
                    let formal = format!("{}{}",io,gf);
                    let actual = format!("{}",g.actual); 
                    if self.mode(&d.entity_name,&gf) == Mode::In {
                        one_com.push((formal,actual));
                    } else {
                        one_com.push((actual,formal));
                    }
                }
            }
            let mut one = vals(one_com,2).iter()
                .map(|x| x.as_str().replace("=",":=").replace("val ",""))
                .collect();
            result.append(&mut one);
        }
        result
    }

    pub fn declare_instances(&self) -> String {
        self.instances_strings().join("\n")
    }

    pub fn instances(&self) -> impl Iterator<Item = &Instance> {
        self.instances.values()
    }    
}

pub struct Database {
    entities: FnvHashMap<String, Entity>,
    architecture: FnvHashMap<String, Architecture>,
}
impl Database {
    pub fn from(project: &Project) -> Database {
        let mut entities = FnvHashMap::default();
        for en in Entity::all(project) {
            entities.insert(en.ident.to_uppercase(),en.clone());
        }
        Database {
            entities,
            architecture: FnvHashMap::default(),
        }
    }
    pub fn get_entity(&self,id: String) -> Option<&Entity> {
        let uid = id.to_uppercase();
        self.entities.get(&uid)
    }
    pub fn entities(&self) -> impl Iterator<Item = &Entity> {
        self.entities.values()
    }
}
pub fn instance_of_arch(ar:&ArchitectureBody) -> String {
    let mut result: Vec<(String,String)> = Vec::new();
    for d in ar.statements.clone() {
        match d.statement {
            ConcurrentStatement::Instance(u) => { 
                let label = format!("{}",d.label.unwrap().item.name());
                let mut comp = String::new();
                match u.unit {
                    InstantiatedUnit::Component(c) => {
                        comp += &format!("{}",c.item);
                    },
                    _ => (),
                }
                comp += "(";
                let mut first = true;
                for g in u.generic_map {
                    if first {
                        first = false;
                    } else {
                        comp += ",";
                    }
                    comp += &association_element(&g);
                }
                comp += ")";
                result.push((label,comp));
            }
            _ => (),
        }
    }
    val(result,2)
}

pub fn comp_io_of_arch(ar:&ArchitectureBody) -> String {
    let mut result = String::new();
    for d in ar.statements.clone() {
        match d.statement {
            ConcurrentStatement::Instance(u) => { 
                let io = format!("{}.io.",d.label.unwrap().item.name());
                for g in u.port_map {
                    let actual = to_str(&g.actual);
                    if let Some(name) = g.formal.clone() {
                        result += &format!("{}{} := {}\n",io,to_str(&name),actual);
                    }
                }
            }
            _ => (),
        }
    }
    result
}

pub fn dump_io_of_arch(ar:&ArchitectureBody) -> String {
    let mut result = String::new();
    for d in ar.statements.clone() {
        match d.statement {
            ConcurrentStatement::Instance(u) => { 
                let io = format!("{}.io.",d.label.unwrap().item.name());
                let mut counter = 0;
                for g in u.port_map {
                    if let Some(name) = g.formal.clone() {
                        result += &format!("{}{:?} := {:?}\n",io,name,g.actual);
                    }
                    counter += 1;
                    if counter >= 1 {
                        break;
                    }
                }
                match u.unit {
                    InstantiatedUnit::Component(c) => {
                        result += &format!("{:?}\n",c);
                    },
                    _ => (),
                }
            }
            _ => (),
        }
    }
    result
}
#[derive(PartialEq, Debug, Clone)]
pub struct ConditionalSpinal<T> {
    pub condition: Expr,
    pub item: T,
}
impl ConditionalSpinal<SequentialStatementSpinal> {
    pub fn vecfrom(c:&Conditional<Vec<LabeledSequentialStatement>>) -> ConditionalSpinal<Vec<SequentialStatementSpinal>> {
        ConditionalSpinal {
            condition:Expr::from(&c.condition.item),
            item: c.item.iter().map(|c| SequentialStatementSpinal::from(c)).collect::<Vec<_>>(),
        }
    }
}
impl fmt::Display for ConditionalSpinal<Vec<SequentialStatementSpinal>> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let ifs :Vec<String> = self.item.iter().map(|i| format!("{}",i)).collect();
        write!(f,"if({}) {{\n{}\n}}",self.condition,ifs.join("\n"))
    }
}
#[derive(PartialEq, Debug, Clone)]
pub struct ConditionalSpinals<T> {
    pub conditionals: Vec<ConditionalSpinal<T>>,
    pub else_item: Option<T>,
}

pub type IfStatementSpinal = ConditionalSpinals<Vec<SequentialStatementSpinal>>;
pub type LoopStatementSpinal = Vec<SequentialStatementSpinal>;
impl fmt::Display for ConditionalSpinals<Vec<SequentialStatementSpinal>> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let ifs : Vec<String> = self.conditionals.iter().map(|i| format!("{}",i)).collect();
        let el = if let Some(es) = &self.else_item {
            let ess : Vec<String> = es.iter().map(|i| format!("{}",i)).collect();
            format!("else {{\n{}\n}}",ess.join("\n"))
        } else {
            String::new()
        };
        write!(f,"{}\n{}",ifs.join("\n"),el)
    }
}
#[derive(PartialEq, Debug, Clone)]
pub enum SequentialStatementSpinal {
    If(IfStatementSpinal),
    Loop(LoopStatementSpinal),
    SignalAssignment(SignalAssignmentSpinal),
    Case(CaseStatementSpinal),
    Unsupport(&'static str),
}
impl SequentialStatementSpinal {
    pub fn from(s:&LabeledSequentialStatement) -> SequentialStatementSpinal {
        match &s.statement {
            SequentialStatement::If(ifs) => {
                let ifo = IfStatementSpinal {
                    conditionals: ifs.conditionals.iter()
                        .map(|c| ConditionalSpinal::vecfrom(c)).collect::<Vec<_>>(),
                    else_item: ifs.else_item.as_ref().map(|t| t.iter()
                        .map(|c| SequentialStatementSpinal::from(c)).collect::<Vec<_>>()),
                };
                SequentialStatementSpinal::If(ifo)
            },
            SequentialStatement::SignalAssignment(sa) => 
                SequentialStatementSpinal::SignalAssignment(SignalAssignmentSpinal::from(sa)),
            SequentialStatement::Case(cs) => 
                SequentialStatementSpinal::Case(CaseStatementSpinal::from(cs)),
            _ => SequentialStatementSpinal::Unsupport("Unkown"),
        }
    }
}
impl fmt::Display for SequentialStatementSpinal {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            SequentialStatementSpinal::If(ifs)=> write!(f,"{}\n",ifs),
            SequentialStatementSpinal::SignalAssignment(sa)=> write!(f,"{}\n",sa),
            SequentialStatementSpinal::Case(cs)=> write!(f,"{}\n",cs),
            _ => write!(f,"Unsupport\n"),
        }
    }
}


#[derive(PartialEq, Debug, Clone)]
pub struct ProcessSpinal {
    pub sensitivity_list: Vec<String>,
    pub statements: Vec<SequentialStatementSpinal>,
}

impl ProcessSpinal {
    pub fn from(p:&ProcessStatement) -> ProcessSpinal {
        let mut sensitivity_list = Vec::new();
        p.sensitivity_list.as_ref().map(|s|
            match s {
                SensitivityList::Names(names) => {
                    names.iter().for_each(|n| sensitivity_list.push(to_str(n)));
                },
                _ => (),
            });
        let statements = p.statements.iter().map(|s| SequentialStatementSpinal::from(s)).collect::<Vec<_>>();
        ProcessSpinal {
            sensitivity_list,
            statements,
        }
    }
}
impl fmt::Display for ProcessSpinal {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let parameters : Vec<String> = self.sensitivity_list.iter().map(|sl| sl.clone()).collect();
        let body : Vec<String> = self.statements.iter().map(|s| format!("{}",s)).collect();
        write!(f,"process({})\n{}",parameters.join(","),body.join("\n"))
    }
}

#[derive(PartialEq, Debug, Clone)]
pub struct SignalAssignmentSpinal {
    pub target: String,
    pub rhs: Expr,    
}

impl SignalAssignmentSpinal {
    pub fn from(sa:&SignalAssignment) -> SignalAssignmentSpinal {
        let target = String::from(to_str(&sa.target));
        let mut rhs = Expr::default();
        match &sa.rhs {
            AssignmentRightHand::Simple(Waveform::Elements(v)) => {
                rhs = Expr::from(&v[0].value.item);
            },
            _ => (),
        }
        SignalAssignmentSpinal {
            target,
            rhs,
        }
    }
}
impl fmt::Display for SignalAssignmentSpinal {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,"{} := {}\n",self.target,self.rhs)
    }
}
#[derive(PartialEq, Debug, Clone)]
pub struct CaseStatementSpinal {
    pub is_matching: bool,
    pub expression: Expr,
    pub alternatives: Vec<AlternativeSpinal<Vec<SequentialStatementSpinal>>>,
}
impl fmt::Display for CaseStatementSpinal {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let al : Vec<String> = self.alternatives.iter().map(|a| format!("{}",a)).collect();

        write!(f,"switch({})\n{}",self.expression,al.join("\n"))
    }
}
#[derive(PartialEq, Debug, Clone)]
pub struct AlternativeSpinal<T> {
    pub choices: Vec<String>,
    pub item: T,
}
impl fmt::Display for AlternativeSpinal<Vec<SequentialStatementSpinal>> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let al : Vec<String> = self.item.iter().map(|a| format!("{}",a)).collect();
        write!(f,"when({}) {{\n{}\n}}",self.choices.join(","),al.join("\n"))
    }
}
impl AlternativeSpinal<Vec<SequentialStatementSpinal>> {
    pub fn from(a:&Alternative<Vec<LabeledSequentialStatement>>) -> AlternativeSpinal<Vec<SequentialStatementSpinal>> {
        let choices = a.choices.iter().map(|c| 
            match c {
                Choice::Expression(e) => to_str(e),
                Choice::DiscreteRange(dr) => match dr {
                    DiscreteRange::Range(Range::Range(r)) => {
                        range2str(&r)
                    },
                    _ => format!("Discrete {:?}",dr),
                },
                _ => format!("Others {:?}",c),
            }
        ).collect();
        let item = a.item.iter().map(|c| SequentialStatementSpinal::from(c)).collect();
        AlternativeSpinal {
            choices,
            item,
        }    
    }
}

impl CaseStatementSpinal {
    pub fn from(cs:&CaseStatement) -> CaseStatementSpinal {
        let is_matching = cs.is_matching;
        let expression = Expr::from(&cs.expression.item);
        let alternatives = cs.alternatives.iter()
            .map(|c| AlternativeSpinal::from(c))
            .collect();
        CaseStatementSpinal {
            is_matching,
            expression,
            alternatives,
        }
    }
}

#[derive(PartialEq, Debug, Clone)]
pub struct FunctionCallSpinal  {
    pub name: Name,
    pub parameters: Vec<AssElement>,
}

impl<'a> From<&'a FunctionCall> for FunctionCallSpinal {
    fn from(f:&FunctionCall) -> Self {
        FunctionCallSpinal {
            name: f.name.item.clone(),
            parameters: f.parameters.iter().map(|a| AssElement::from(&a)).collect(),
        }
    }
}

impl fmt::Display for FunctionCallSpinal {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let parameters : Vec<String> = self.parameters.iter().map(|ae| ae.val()).collect();
        write!(f,"{}({})",NameDisplay::from(&self.name),parameters.join(","))
    }
}

#[derive(PartialEq, Debug, Clone)]
pub enum NameSpinal {
    Designator(DesignatorSpinal),
    Selected(Box<NameSpinal>, DesignatorSpinal),
    SelectedAll(Box<NameSpinal>),
    Indexed(Box<NameSpinal>, Vec<Expr>),
    Slice(Box<NameSpinal>, Box<DiscreteRange>),
    // Attribute(Box<AttributeName>),
    FunctionCall(Box<FunctionCallSpinal>),
    // External(Box<ExternalName>),
    Nosupport,
}
impl<'a> From<&'a Name> for NameSpinal {
    fn from(n:&Name) -> Self {
        match n {
            Name::Designator(d) => NameSpinal::Designator(DesignatorSpinal::from(&d.item)),
            Name::Selected(n,d) => NameSpinal::Selected(
                Box::new(NameSpinal::from(&n.item)),
                DesignatorSpinal::from(&d.item.item)
            ),
            Name::SelectedAll(n) => NameSpinal::SelectedAll(
                Box::new(NameSpinal::from(&n.item))
            ),
            Name::Indexed(n,ve) => NameSpinal::Indexed(
                Box::new(NameSpinal::from(&n.item)),
                ve.iter().map(|x| Expr::from(&x.item)).collect()
            ),
            Name::FunctionCall(f) => NameSpinal::FunctionCall(
                Box::new(FunctionCallSpinal::from(&**f))
            ),
            _ => NameSpinal::Nosupport,
        }
    }
}
impl fmt::Display for NameSpinal {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let result = match self {
            NameSpinal::Designator(d) => 
                match &d {
                    DesignatorSpinal::Identifier(s) => format!("{}",s),
                    DesignatorSpinal::OperatorSymbol(s) => format!("{}",s),
                    DesignatorSpinal::Character(s) => format!("{}",s),
                },
            NameSpinal::Selected(n, d) => format!("{}{}", n, d),
            NameSpinal::SelectedAll(n) => format!("{}",n),
            NameSpinal::Indexed(n, ve) => format!("{}({})",n,ve2str(ve)),
            NameSpinal::Slice(n,r) =>  format!("{}({})", n, DiscreteRangeSpinal::from(&**r)),
            NameSpinal::FunctionCall(f) => format!("{}",f),
            _ => String::new(),
        };
        write!(f, "{}", result)
    }
}

#[derive(PartialEq, Debug, Clone)]
pub enum DiscreteRangeSpinal {
    Discrete(SelectedNameSpinal, Option<RangeSpinal>),
    Range(RangeSpinal),
}
impl<'a> From<&'a DiscreteRange> for DiscreteRangeSpinal {
    fn from(n:&DiscreteRange) -> Self {
        match n {
            DiscreteRange::Discrete(s,r) => DiscreteRangeSpinal::Discrete(
                SelectedNameSpinal::from(&s.item),
                r.as_ref().map(|r| RangeSpinal::from(r)),
            ),
            DiscreteRange::Range(r) => DiscreteRangeSpinal::Range(RangeSpinal::from(r)),
        }
    }
}
impl fmt::Display for DiscreteRangeSpinal {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            DiscreteRangeSpinal::Discrete(s,Some(r)) => write!(f, "{}{}", s, r),
            DiscreteRangeSpinal::Discrete(s,None) => write!(f, "{}", s),
            DiscreteRangeSpinal::Range(r) => write!(f, "{}", r),
        }
    }
}
#[derive(PartialEq, Debug, Clone)]
pub struct RangeSpinal {
    pub direction: Direction,
    pub left_expr: Box<Expr>,
    pub right_expr: Box<Expr>,
}
impl std::default::Default for RangeSpinal {
    fn default() -> Self {
        RangeSpinal { 
            direction: Direction::Descending, 
            left_expr: Box::new(Expr::default()), 
            right_expr: Box::new(Expr::default()) 
        }
    }
}
impl<'a> From<&'a Range> for RangeSpinal {
    fn from(n:&Range) -> Self {
        match n {
            Range::Range(rc) => RangeSpinal {
                direction: rc.direction,
                left_expr: Box::new(Expr::from(&rc.left_expr.item)),
                right_expr: Box::new(Expr::from(&rc.right_expr.item)),
            },
            _ => Self::default(),
        }
    }
}
impl fmt::Display for RangeSpinal {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let direction = match self.direction {
            Direction::Descending => String::from("downto"),
            _ => String::from("to"),
        };
        write!(f, "({} {} {})",self.left_expr,direction,self.right_expr)
    }
}

#[derive(PartialEq, Debug, Clone)]
pub enum SelectedNameSpinal {
    Designator(DesignatorSpinal),
    Selected(Box<SelectedNameSpinal>, DesignatorSpinal),
}
impl<'a> From<&'a SelectedName> for SelectedNameSpinal {
    fn from(n:&SelectedName) -> Self {
        match n {
            SelectedName::Designator(d) => SelectedNameSpinal::Designator(DesignatorSpinal::from(&d.item)),
            SelectedName::Selected(s,d) => SelectedNameSpinal::Selected(
                Box::new(SelectedNameSpinal::from(&s.item)),
                DesignatorSpinal::from(&d.item.item)
            ),
        }
    }
}
impl fmt::Display for SelectedNameSpinal {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            SelectedNameSpinal::Designator(d) => write!(f, "{}", d),
            SelectedNameSpinal::Selected(s,d) => write!(f, "{}={}", s,d),
        }
    }
}
#[derive(PartialEq, Debug, Clone)]
pub enum DesignatorSpinal {
    Identifier(String),
    OperatorSymbol(String),
    Character(u8),
}
impl<'a> From<&'a Designator> for DesignatorSpinal {
    fn from(n:&Designator) -> Self {
        match n {
            Designator::Identifier(s) => DesignatorSpinal::Identifier(format!("{}",s.name())),
            Designator::OperatorSymbol(s) => DesignatorSpinal::OperatorSymbol(format!("{}",s)),
            Designator::Character(s) => DesignatorSpinal::Character(*s),            
        }
    }
}
impl fmt::Display for DesignatorSpinal {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            DesignatorSpinal::Identifier(s) => write!(f, "{}", s),
            DesignatorSpinal::OperatorSymbol(s) => write!(f, "{}", s),
            DesignatorSpinal::Character(s) => match s {
                b'0' => write!(f, "Fasle"),
                b'1' => write!(f, "True"),
                _ => write!(f, "{}",s),
            },
        }
    }
}

#[derive(PartialEq, Debug, Clone)]
pub struct NameDisplay {
    pub name:Name
}

impl<'a> From<&'a Name> for NameDisplay {
    fn from(n:&Name) -> Self {
        NameDisplay {
            name:n.clone()
        }
    }
}

impl<'a> From<&'a Box<Name>> for NameDisplay {
    fn from(n:&Box<Name>) -> Self {
        NameDisplay::from(&**n) 
    }
}


fn vpe2str(ve:&Vec<WithPos<Expression>>) -> String {
    let mut result = Vec::new();
    for e in ve {
        result.push(to_str(e));
    }
    result.join(",")
} 



fn ve2str(ve:&Vec<Expr>) -> String {
    let mut result = Vec::new();
    for e in ve {
        result.push(format!("{}",e));
    }
    result.join(",")
} 


impl fmt::Display for NameDisplay {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let result = match &self.name {
            Name::Designator(d) => if let Some(r) = &d.reference {
                get_pos_str(&r)
            }else {
                match &d.item {
                    Designator::Identifier(s) => format!("{}",s.name()),
                    Designator::OperatorSymbol(s) => format!("{}",s),
                    Designator::Character(s) => format!("{}",s),
                }
            },
            Name::Selected(n, d) => to_str(&n) + &to_str(&d),
            Name::SelectedAll(n) => to_str(&n),
            Name::Indexed(n, ve) => to_str(&n)+"("+
                &vpe2str(&ve)+")",
            Name::Slice(n,r) =>  to_str(&n)+&disrange2str(&r),
            Name::Attribute(a) => format!("{:?}",a),
            Name::FunctionCall(f) => format!("{}",FunctionCallSpinal::from(&**f)),
            _ => String::new(),
        };
        write!(f, "{}", result)
    }
}